﻿using Recipes.Model;
using Recipes.ViewModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.System;
using Windows.UI;
using Windows.UI.StartScreen;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Basic Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234237

namespace Recipes.Pages
{

    /// <summary>
    /// A basic page that provides characteristics common to most applications.
    /// </summary>
    public sealed partial class RecipePage : Recipes.Common.LayoutAwarePage, INotifyPropertyChanged
    {
        //La ricetta associata alla pagina
        private Recipe _recipe;

        //booleano che indica se la ricetta è stata caricata da una secondary tile o no
        private bool _fromPin;

        /// <summary>
        /// Ottiene la visibilità del bottone Pin
        /// </summary>
        public string PinVisibility
        {
            get { return _fromPin ? "Collapsed" : "Visible"; }
        }

        /// <summary>
        /// Ottiene la visibilità del bottone UnPin
        /// </summary>
        public string UnPinVisibility
        {
            get { return _fromPin ? "Visible" : "Collapsed"; }
        }

        /// <summary>
        /// Costruttore della pagina
        /// </summary>
        public RecipePage()
        {
            this.InitializeComponent();
            _recipe = null;
            _fromPin = false;
            //Imposta il DataContext dell'application bar
            BottomAppBarStackPanel.DataContext = this;                       
        }




        /// <summary>
        /// Metodo invocato quando l'utente apre il Charm Share
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        void RecipePage_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
        {
            //Preparo il contenuto da condividere.
            DataRequest request = args.Request;
            request.Data.Properties.Title = _recipe.Title;                       
            //request.Data.SetUri(_recipe.Link);
            request.Data.SetText(_recipe.Summary);
        }

        /// <summary>
        /// Populates the page with content passed during navigation.  Any saved state is also
        /// provided when recreating a page from a prior session.
        /// </summary>
        /// <param name="navigationParameter">The parameter value passed to
        /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
        /// </param>
        /// <param name="pageState">A dictionary of state preserved by this page during an earlier
        /// session.  This will be null the first time a page is visited.</param>
        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
        }

        /// <summary>
        /// Preserves state associated with this page in case the application is suspended or the
        /// page is discarded from the navigation cache.  Values must conform to the serialization
        /// requirements of <see cref="SuspensionManager.SessionState"/>.
        /// </summary>
        /// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
        protected override void SaveState(Dictionary<String, Object> pageState)
        {
        }

        /// <summary>
        /// Metodo invocato quando si naviga a questa pagina.
        /// Viene utilizzato per inizializzare alcuni contenuti della pagina
        /// </summary>
        /// <param name="e"></param>
        protected async override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);

            //Si registra all'evento legato alla condivisione dei contenuti
            DataTransferManager.GetForCurrentView().DataRequested += RecipePage_DataRequested;

            //Ottengo l'id dai parametri di navigazione
            Guid guid = (Guid)e.Parameter;
            
            //Se ci sono ricette scaricate, ottengo la ricetta da quelle scaricate
            if(App.downloadedRecipes != null)
                _recipe = App.downloadedRecipes.Where(x => x.Guid == guid).FirstOrDefault<Recipe>();
            
            if (_recipe == null)
            {
                //Se non ho trovato la ricetta, allora devo leggere la ricetta da file.
                //Costruisco il nome del file
                string filename = guid.ToString();
                //Leggo la ricetta
                _recipe = await readRecipeFromStorage(filename);

                //Imposto il booleano che indica la lettura della ricetta da file
                //e il lancio dell'app da una tile secondaria.
                _fromPin = true;
                notifyPropertyChanged("PinVisibility");
                notifyPropertyChanged("UnPinVisibility");
            }

            //Imposto il DataContext della pagina
            DataContext = new RecipeViewModel(_recipe);
        }

        protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            base.OnNavigatingFrom(e);

            DataTransferManager.GetForCurrentView().DataRequested -= RecipePage_DataRequested;

        }


        /// <summary>
        /// Metodo invocato quando l'utente clicca sull'HyperlinkButton
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void LinkBtn_Tapped(object sender, TappedRoutedEventArgs e)
        {
            HyperlinkButton hBtn = sender as HyperlinkButton;
            if (hBtn != null)
            {
                //Ottengo l'uri verso cui far navigare l'utente
                Uri u = hBtn.Tag as Uri;
                if (u != null)
                {
                    //Faccio navigare l'utente verso l'Uri desiderato.
                    await Launcher.LaunchUriAsync(u);
                }
            }
        }

        /// <summary>
        /// Metodo invocato quando l'utente clicca sul bottone Pin
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void PinAsSecondaryTile_Click_1(object sender, RoutedEventArgs e)
        {
            //Salva la ricetta su disco
            await saveRecipeInStorage();
            //Crea la tile secondaria
            SecondaryTile secTile = new SecondaryTile(_recipe.Guid.ToString(), _recipe.Title, _recipe.Title, _recipe.Guid.ToString(),
                TileOptions.ShowNameOnLogo | TileOptions.ShowNameOnWideLogo, new Uri("ms-appx:///Assets/RecipeLogo.Png", UriKind.Absolute),
                new Uri("ms-appx:///Assets/RecipeWideLogo.Png", UriKind.Absolute));            

            //Pin la tile secondaria
            bool isPinned = await secTile.RequestCreateAsync();
            if (!isPinned)
            {
                Debug.WriteLine("Something wrong: not pinned");
            }
        }

        /// <summary>
        /// Metodo utilizzato per leggere la ricetta da file
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private async Task<Recipe> readRecipeFromStorage(string fileName)
        {
            //Preparo la ricetta da restituire
            Recipe toRet = null;
            //Ottengo la cartella in cui si trova la ricetta
            StorageFolder folder = ApplicationData.Current.LocalFolder;
            //Ottengo il file della ricetta
            StorageFile file = await folder.GetFileAsync(fileName);
            //Apro uno stream per leggere il contenuto del file
            using (Stream stream = await file.OpenStreamForReadAsync())
            {
                //Creo un oggetto che mi aiuta nella deserializzazione della ricetta
                DataContractSerializer serializer = new DataContractSerializer(typeof(Recipe)); 
                //Leggo la ricetta dal file
                toRet = serializer.ReadObject(stream) as Recipe;
                
            }
            //restituisco la ricetta
            return toRet;
        }

        /// <summary>
        /// Metodo invocato per salvare la ricetta su un file
        /// </summary>
        /// <returns></returns>
        private async Task saveRecipeInStorage()
        {
            //Ottengo la cartella in cui si trova la ricetta
            StorageFolder folder = ApplicationData.Current.LocalFolder;
            //Creo il file della ricetta
            StorageFile file = await folder.CreateFileAsync(_recipe.Guid.ToString(), 
                CreationCollisionOption.ReplaceExisting);
            //Apro uno stream per leggere il contenuto del file      
            using (Stream stream = await file.OpenStreamForWriteAsync())
            {
                //Creo un oggetto che mi aiuta nella serializzazione della ricetta
                DataContractSerializer serializer = new DataContractSerializer(typeof(Recipe));
                //Scrivo la ricetta sul file
                serializer.WriteObject(stream, _recipe);
                
            } 
             
        }

        /// <summary>
        /// Metodo invocato quando l'utente clicca sul pulsante UnPin
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void UnPinSecondaryTile_Click_1(object sender, RoutedEventArgs e)
        {            
            //Se esiste la Tile secondaria che ha come nome il Guid del file
            if (SecondaryTile.Exists(_recipe.Guid.ToString()))
            {
                //Ottengo la tile secondaria
                SecondaryTile secTile = (await SecondaryTile.FindAllAsync())
                    .Where(x => x.TileId == _recipe.Guid.ToString()).FirstOrDefault();
                if (secTile != null)
                {
                    //Richiedo l'eliminazione della Tile secondaria
                    bool deleted = await secTile.RequestDeleteAsync();
                    if (deleted)
                    {
                        //Ottengo la cartella in cui si trova la ricetta
                        StorageFolder folder = ApplicationData.Current.LocalFolder;
                        //Ottengo il file della ricetta
                        StorageFile file = await folder.GetFileAsync(_recipe.Guid.ToString());
                        //Elimino il file
                        await file.DeleteAsync();

                        //Imposto il booleano per poterla eventualmente risalvare.
                        _fromPin = false;
                        notifyPropertyChanged("PinVisibility");
                        notifyPropertyChanged("UnPinVisibility");
                    }
                }
            }

        }

        /// <summary>
        /// Evento dell'interfaccia INotifyPropertyChanged
        /// Necessario per collegare la UI con il codice.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;       
        private void notifyPropertyChanged(string p)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(p));
        }

        
    }
}
